﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Skyhook.Core;

namespace Skyhook.Sprites
{
    internal class SpriteWorldVisualizer
    {
        GraphicsDevice GraphicsDevice = null;

        IOnScreenView View = null;

        SpriteBatch pSpriteBatch = null;

        DepthStencilState ShadowDepthTest = null;
        AlphaTestEffect AlphaTest = null;

        VertexPositionColor[] GridVertex = null;
        BasicEffect GridEffect = null;

        int pSpritesOnScreen = 0;

        List<SpriteObject> Sprites = new List<SpriteObject>();

        public SpriteWorldVisualizer(IOnScreenView view, Microsoft.Xna.Framework.Game game)
        {
            GraphicsDevice = game.GraphicsDevice;
            View = view;

            pSpriteBatch = new SpriteBatch(GraphicsDevice);

            ShadowDepthTest = new DepthStencilState();
            ShadowDepthTest.DepthBufferEnable = true;
            ShadowDepthTest.DepthBufferWriteEnable = true;
            ShadowDepthTest.DepthBufferFunction = CompareFunction.Less;

            AlphaTest = new AlphaTestEffect(GraphicsDevice);
            AlphaTest.VertexColorEnabled = true; 
            AlphaTest.AlphaFunction = CompareFunction.Greater;
            AlphaTest.ReferenceAlpha = 0; 
            AlphaTest.World = Matrix.Identity;
            AlphaTest.View = Matrix.Identity; 
            AlphaTest.Projection = SpriteProjection.OrthohraphicProjectionMatrix;

            GridEffect = new BasicEffect(GraphicsDevice);
            GridEffect.VertexColorEnabled = true;
            GridEffect.World = Matrix.Identity;
            GridEffect.View = Matrix.Identity;
            GridEffect.Projection = Matrix.Identity;
            GridEffect.TextureEnabled = false;

            GridVertex = new VertexPositionColor[(128 + 1) * (128 + 1) * 2];
            for (int y = 0; y < 128 + 1; y++)
            {
                GridVertex[y * 2].Color = Color.Red;
                GridVertex[y * 2].Position = new Vector3(0.0f, y, 0.0f);
                GridVertex[y * 2 + 1].Color = Color.Red;
                GridVertex[y * 2 + 1].Position = new Vector3(128, y, 0.0f);
            }
            for (int x = 0; x < 128 + 1; x++)
            {
                GridVertex[(128 + 1) * 2 + x * 2].Color = Color.Red;
                GridVertex[(128 + 1) * 2 + x * 2].Position = new Vector3(x, 0.0f, 0.0f);
                GridVertex[(128 + 1) * 2 + x * 2 + 1].Color = Color.Red;
                GridVertex[(128 + 1) * 2 + x * 2 + 1].Position = new Vector3(x, 128, 0.0f);
            }
        }
         
        public virtual void RenderSprites()
        {
            Matrix shift = Matrix.CreateTranslation(-View.LeftTop.X, -View.LeftTop.Y, 0);

            /*Matrix WorldToScreen = new Matrix();
            WorldToScreen = Matrix.CreateRotationZ(45.0f * 2 * (float)Math.PI / 360.0f);
            WorldToScreen *= Matrix.CreateScale(1, (float)(32 / Math.Sqrt(2.0)), 1);
            WorldToScreen *= Matrix.CreateScale((float)(64 / Math.Sqrt(2.0)), 1, 1);

            GridEffect.Projection = WorldToScreen * shift * SpriteProjection.OrthohraphicProjectionMatrix;

            foreach (EffectPass pass in GridEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, GridVertex, 0, (128 + 1) * (128 + 1));
            }*/

            Sprites.Clear();

            IVisual currentvisual = View.GetFirstVisual();
            while (currentvisual != null)
            {
                Sprites.Add((SpriteObject)currentvisual);
                currentvisual = View.GetNextVisual();
            }

            pSpritesOnScreen = Sprites.Count;
            
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,SamplerState.LinearClamp,DepthStencilState.None,RasterizerState.CullNone,null,shift);
            for (int i = SpriteLayers.Minimum; i < SpriteLayers.Shadow; i++)
            {
                foreach (SpriteObject sprite in Sprites)
                {
                    sprite.Render(SpriteBatch, i);
                }
            }
            SpriteBatch.End();

            GraphicsDevice.Clear(ClearOptions.DepthBuffer, new Color(0, 0, 0, 0), 1, 0);
            AlphaTest.Projection = shift * SpriteProjection.OrthohraphicProjectionMatrix;

            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearClamp, ShadowDepthTest, RasterizerState.CullNone, AlphaTest);
            for (int i = SpriteLayers.Shadow; i <= SpriteLayers.Shadow; i++)
            {
                foreach (SpriteObject sprite in Sprites)
                {
                    sprite.Render(SpriteBatch, i, Color.White, 0.1f);
                }
            }
            SpriteBatch.End();

            GraphicsDevice.Clear(ClearOptions.DepthBuffer, new Color(0, 0, 0, 0), 1, 0);
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, AlphaTest);
            foreach (SpriteObject sprite in Sprites)
            {
                sprite.Render(SpriteBatch, SpriteLayers.Huge);
            }
            SpriteBatch.End();

            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearClamp, DepthStencilState.DepthRead, RasterizerState.CullNone, AlphaTest);
            for (int i = SpriteLayers.Unit_1; i <= SpriteLayers.Maximum; i++)
            {
                foreach (SpriteObject sprite in Sprites)
                {
                    sprite.Render(SpriteBatch, i);
                }
            }
            SpriteBatch.End();

        }
        public SpriteBatch SpriteBatch
        {
            get
            {
                return pSpriteBatch;
            }
        }

        public int SpritesOnScreen
        {
            get
            {
                return pSpritesOnScreen;
            }
        }
    }
}
